
const {getAst, getCode,getDeps} = require('./Parser.js')
const fs = require('fs')
const path =  require("path")

class Compiler {
  constructor(options={}){
    this.options = options
    // 所有依赖的容器
    this.modules = []
  }
  // 启动webpack
  run(){
    const filepath = this.options.entry   // 入口文件路径
    // 第一次构建 得到入口文件信息
    const fileinfo = this.build(filepath)
    this.modules.push(fileinfo)
    // this.modules.forEach((fileinfo)=>{
    // const deps = fileinfo.deps
    //   for (const relativepath in deps) {
    //     const absolutepath = deps[relativepath]
    //     console.log(absolutepath);
    //     const fileinfo = this.build(absolutepath)
    //     this.modules.push(fileinfo)
    //   } 
    // })
    const getDepsMethod = (deps) => {
      for (const key in deps) {
        const fileinfo = this.build(deps[key])
        this.modules.push(fileinfo)
        if(JSON.stringify(fileinfo.deps) != {}){
          getDepsMethod(fileinfo.deps)
        }
      }
  }
  //递归依赖
  getDepsMethod(fileinfo.deps)
    // console.log(fileinfo.deps);

    // 将依赖整理成更好的关系依赖图

    const depsGraph = this.modules.reduce((graph,module)=>{
      return {
        ...graph,
        [module.filepath]: {
          code: module.code,
          deps: module.deps
        }
      }
    },{})

    // console.log(depsGraph);
    this.generate(depsGraph)
  }
  build(filepath) {
    const ast = getAst(filepath)    
    const deps = getDeps(ast, filepath)
    const code  = getCode(ast)

    return {
      filepath,
      deps,
      code
    }
  }
  // 生成输出资源
  generate(depsGraph){
    const bundle = `
    (function (depsGraph) {
      function require(module) {
        function localRequire(relativepath) {
          return require(depsGraph[module].deps[relativepath]);
        }

        var exports = {};
        (function(require,exports,code) {
          eval(code);
        })(localRequire, exports, depsGraph[module].code)
        return exports;
      }
      require('${this.options.entry}')
    })(${JSON.stringify(depsGraph)})
    `
    const filepath = path.resolve(this.options.output.path, this.options.output.filename)
    fs.writeFileSync(filepath,bundle,'utf-8')
  }
}

module.exports = Compiler